import json
import random
import re
from datetime import datetime, timedelta
from math import ceil

from flask import request, current_app, g
from flask_restful import Resource
from sqlalchemy import desc

from model.news import Channel, UserChannel, Article, Comment, Attitude, Collection, CommentLiking, Read
from model.user import User, UserProfile, Relation
from toutiao import redis_cli, db, app

from utils.jwt import generate_jwt, verify_jwt
from utils.login_required import login_required

from utils.send_message import send_messages


class UserResouce(Resource):
    def get(self, mobile):
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return {'code': 400, 'message': '参数mobile有误'}
        code = str(random.randint(1000, 9999))
        # 通过方法来进行发送短信
        # mobile = send_messages(mobile,code)
        # 在控制台中输出我们需要的验证码
        print(code)
        # 把验证码存入我们的redis当中
        redis_cli.setex(mobile, 120, code)
        # 进行返回给前端数据
        return {'message': 'ok,', 'data': {'mobile': mobile}}


class AuthorizationResource(Resource):
    """
    认证
    """

    def _generate_tokens(self, user_id, with_refresh_token=True):
        """
        生成token 和refresh_token
        :param user_id: 用户id
        :return: token, refresh_token
        """
        # 颁发JWT
        now = datetime.utcnow()  # 获取当前时间
        expiry = now + timedelta(hours=2)  # 计算token过期时间
        token = generate_jwt({'user_id': user_id, 'refresh': False}, expiry)  # 生成token
        refresh_token = None  # 初始化刷新token
        if with_refresh_token:  # 判断是否需要刷新token
            refresh_expiry = now + timedelta(days=current_app.config['JWT_REFRESH_DAYS'])  # 计算刷新token过期时间
            refresh_token = generate_jwt({'user_id': user_id, 'refresh': True}, refresh_expiry)  # 生成刷新token
        return token, refresh_token  # 返回token和刷新token


    def post(self):
        """
        登录创建token
        """
        # 从前端获取到我们的数据
        data = json.loads(request.data.decode())
        mobile = data.get('mobile')
        code = data.get('code')
        # 从redis中获取验证码
        key = 'app:code:{}'.format(mobile)
        # 进行获取我们存入redis的验证码
        try:
            real_code = redis_cli.get(mobile)
        except ConnectionError as e:
            current_app.logger.error(e)
            real_code = redis_cli.get(mobile)
        try:
            redis_cli.delete(mobile)
        except ConnectionError as e:
            current_app.logger.error(e)
        if not real_code or real_code.decode() != code:
            return {'message': 'Invalid code.'}, 400
        # 查询或保存用户
        user = User.query.filter_by(mobile=mobile).first()
        if user is None:
            # 用户不存在，注册用户
            user_id = User.query.all()[-1].id + 1
            user = User(id=user_id, mobile=mobile, name=mobile, last_login=datetime.now())
            db.session.add(user)
            profile = UserProfile(id=user.id)
            db.session.add(profile)
            db.session.commit()
        else:
            # 验证我们的数据是否存在
            if user.status == User.STATUS.DISABLE:
                return {'message': 'Invalid user.'}, 403
        # 调用方法生成我们的token和refresh_token
        token, refresh_token = self._generate_tokens(user.id)
        # return {'token': token, 'refresh_token': refresh_token}, 201
        return {"message": "ok", "data": {"token": token, "refresh_token": refresh_token}}


    # 补充put方式 更新token接口
    @login_required
    def put(self):
        """
        刷新token
        """
        # 获取我们的对象
        id = g.user_id
        if id and g.is_refresh_token:
            token, refresh_token = self._generate_tokens(id, with_refresh_token=False)
            return {'token': token}, 201
        else:
            return {'message': 'Wrong refresh token.'}, 403


class Userinfo(Resource):
    @login_required
    def get(self):
        following_count = Relation.query.filter_by(user_id=g.user_id).count()  # 查询关注数
        fans_count = Relation.query.filter_by(target_user_id=g.user_id).count()  # 查询粉丝数
        art_count = Article.query.filter_by(user_id=g.user_id).count()  # 查询文章数
        obj = User.query.get(g.user_id)  # 获取用户信息
        response = {
            'message': 'ok',  # 返回消息
            'data': {
                "id": obj.id,  # 用户ID
                "name": obj.name,  # 用户名
                "photo": obj.profile_photo,  # 用户头像
                "intro": obj.introduction,  # 用户介绍
                "art_count": art_count,  # 文章数
                "follow_count": following_count,  # 关注数
                "fans_count": fans_count  # 粉丝数
            }
        }
        return response  # 返回响应


class Channels(Resource):
    @login_required
    def get(self):
        data = Channel.query.all()
        list = []
        for i in data:
            list.append({
                'id': i.id,
                'name': i.name
            })
        return {"message": "OK", "data": {"channels": list}}


# 频道的增删改查
class UserChannleView(Resource):
    @login_required
    def get(self):
        ChannllID = UserChannel.query.filter_by(user_id=g.user_id).all()  # 获取用户的频道ID列表
        data_list = []  # 初始化数据列表
        if len(ChannllID):  # 如果频道ID列表不为空
            for i in ChannllID:  # 遍历频道ID列表
                data_list.append({  # 将频道信息添加到数据列表中
                    'id': i.channel.id,  # 频道ID
                    'name': i.channel.name  # 频道名称
                })
        return {"message": "OK", "data": {"channels": data_list}}  # 返回消息和频道信息


    @login_required
    def put(self):
        channels = json.loads(request.data.decode()).get("channels")
        # 删除数据库中所有用户关联的频道记录
        UserChannel.query.filter_by(user_id=g.user_id).delete()
        # 将列表中的频道信息添加到数据库
        for channel in channels:
            new_record = UserChannel(user_id=g.user_id, channel_id=channel.get('id'), sequence=channel.get('seq'))
            db.session.add(new_record)
        # 保存到数据库
        db.session.commit()
        # 查询所有数据
        channels = UserChannel.query.filter_by(user_id=g.user_id).all()
        # 循环数据到列表 展示给前端
        channel = []
        for i in channels:
            channel.append({"id": i.channel.id, "name": i.channel.name})
        return {"errmsg": "OK", "data": {"channels": channel}}


# 文章列表
class Articles(Resource):
    @login_required
    def get(self):
        dict = request.args
        try:
            channel_id = dict.get('channel_id')
            timestamp = dict.get('timestamp')
            with_top = dict.get('with_top')
        except:
            return 400  # 如果参数获取失败，返回400错误
        data = Article.query.filter_by(channel_id=channel_id).all()  # 查询指定频道的文章
        article_list = []  # 初始化文章列表
        for i in data:  # 遍历查询结果
            article_list.append({  # 将文章信息添加到文章列表中
                'art_id': i.id,  # 文章ID
                'title': i.title,  # 文章标题
                'aut_id': i.user.id,  # 作者ID
                'pubdate': json.dumps(i.ctime, default=str)[1:-1],  # 发布日期
                'aut_name': i.user.name,  # 作者名字
                'comm_count': i.comment_count,  # 评论数
                'is_top': 0,  # 是否置顶
            }
            )
        return {'message': 'ok', 'data': {'pre_timestamp': 2, 'results': article_list}}  # 返回文章列表



# 文章详情页
class ArticlesView(Resource):
    @login_required
    def get(self, article_id):
        i = Article.query.get(article_id)  # 获取指定文章
        attitude_record = Attitude.query.filter_by(article=i).first()  # 查询对文章的态度记录
        followed = Relation.query.filter_by(user_id=g.user_id, target_user_id=i.user_id).first()  # 查询用户是否关注文章的作者
        if Collection.query.filter_by(article_id=i.id, user_id=g.user_id).first() is not None:  # 检查用户是否收藏了该文章
            result = True
        else:
            result = False
        data = {  # 构建文章信息
            "art_id": i.id,  # 文章ID
            "title": i.title,  # 标题
            "pubdate": str(i.ctime),  # 发布日期
            "aut_id": i.user.id,  # 作者ID
            "aut_name": i.user.name,  # 作者名字
            'aut_photo': i.user.profile_photo,  # 作者头像
            "content": i.content.content,  # 文章内容
            "is_followed": False if followed is None else followed.relation,  # 是否关注作者
            "attitude": -1 if attitude_record is None else attitude_record.attitude,  # 文章态度
            "is_collected": result,  # 是否收藏
        }
        aa = Read(user_id=g.user_id, article_id=article_id)  # 记录用户阅读
        if not aa:  # 如果记录不存在
            db.session.add(aa)  # 添加阅读记录
            db.session.commit()  # 提交事务
        return {"message": "ok", "data": data}  # 返回文章信息



# 关注用户和取消关注用户     和获取用户关注

class ArticlesPDView(Resource):
    @login_required
    def post(self):
        data = json.loads(request.data.decode())  # 解析请求数据
        target = data.get('target')  # 获取目标用户ID
        pp = Relation(user_id=g.user_id, target_user_id=target, relation=Relation.RELATION.FOLLOW)  # 创建用户关系
        db.session.add(pp)  # 添加用户关系到数据库会话中
        db.session.commit()  # 提交数据库会话
        return {"message": "OK", "data": {"target": pp.id}}  # 返回成功消息和目标用户ID



class ArticlesPDView2(Resource):
    @login_required
    def delete(self, id):
        target = id  # 获取目标用户ID
        dd = Relation.query.filter_by(user_id=g.user_id, target_user_id=target).first()  # 查询用户关系记录
        db.session.delete(dd)  # 删除用户关系记录
        db.session.commit()  # 提交会话
        return {'message': "ok"}  # 返回成功消息




# 点赞和取消点赞
class ArticlesPoint(Resource):
    @login_required
    def post(self):
        data = json.loads(request.data.decode())  # 解析请求数据
        target = data.get('target')  # 获取目标文章ID
        oo = Attitude.query.filter_by(user_id=g.user_id, article_id=target).first()  # 查询用户对文章的态度记录
        if not oo:  # 如果态度记录不存在
            oo = Attitude(user_id=g.user_id, article_id=target, attitude=Attitude.ATTITUDE.LIKING)  # 创建新的态度记录
            db.session.add(oo)  # 添加态度记录到数据库会话中
            db.session.commit()  # 提交数据库会话
        else:  # 如果态度记录已存在
            oo.attitude = 1  # 更新态度为喜欢
            db.session.commit()  # 提交数据库会话
        return {'message': "ok", 'data': {'target': oo.id}}  # 返回成功消息和目标ID



class ArticlesPoint2(Resource):
    @login_required
    def delete(self, id):
        target = id
        try:
            pp = Attitude.query.filter_by(user_id=g.user_id, article_id=target).first()
            db.session.delete(pp)
            db.session.commit()
        except:
            return 400
        return {'message': 'ok'}


# 喜欢文章
class ArticlesPointDislike(Resource):
    @login_required
    def post(self):
        # 从请求中解析JSON数据
        data = json.loads(request.data.decode())
        # 从数据中获取目标文章ID
        target = data.get('target')
        # 查询用户对文章的态度记录
        oo = Attitude.query.filter_by(user_id=g.user_id, article_id=target).first()
        # 如果态度记录不存在
        if not oo:
            # 创建新的态度记录并将其添加到数据库会话中
            oo = Attitude(user_id=g.user_id, article_id=target, attitude=Attitude.ATTITUDE.LIKING)
            db.session.add(oo)
            db.session.commit()
        # 如果态度记录已存在
        else:
            # 更新态度为喜欢并提交数据库会话
            oo.attitude = 1
            db.session.commit()

        # 返回成功消息和目标ID
        return {'message': "ok", 'data': {'target': oo.id}}



# 和取消点赞
class ArticlesPointDislike2(Resource):
    @login_required
    def delete(self, id):
        target = id  # 获取目标文章ID
        try:
            pp = Attitude.query.filter_by(user_id=g.user_id, article_id=target).first()  # 查询用户对文章的态度记录
            db.session.delete(pp)  # 从数据库中删除态度记录
            db.session.commit()  # 提交数据库会话
        except:
            return 400  # 如果出现异常，返回状态码400
        return {'message': 'ok'}  # 返回成功消息




# 收藏文章和取消收藏文章     用户收藏列表
class ArticlesCollect(Resource):
    def post(self):
        # 从请求数据中解析JSON
        data = json.loads(request.data.decode())
        target = data.get('target')
        aa = Collection.query.filter_by(user_id=g.user_id, article_id=target).first()
        if not aa:
            aa = Collection(user_id=g.user_id, article_id=target)
            db.session.add(aa)
            db.session.commit()
        else:
            aa.attitude = 1
            db.session.commit()  # 提交数据库会话

    def delete(self, id):
        # 获取目标ID
        target = id
        try:
            pp = Collection.query.filter_by(user_id=g.user_id, article_id=target).first()
            db.session.delete(pp)  # 从数据库中删除记录
            db.session.commit()  # 提交数据库会话
        except:
            return 400  # 返回错误状态码

        return {'message': 'ok'}  # 返回成功消息

    def get(self):
        list1 = []  # 用于存储article_id的列表
        list2 = []  # 用于构建结果列表
        list3 = []  # 用于存储Article对象的列表
        list = Collection.query.filter_by(user_id=g.user_id).all()  # 查询用户收藏的所有记录
        for i in list:
            list1.append(i.article_id)  # 将文章ID加入列表中
        for i in list1:
            obj = Article.query.get(i)  # 查询文章对象
            list3.append(obj)  # 将文章对象加入列表中
        for i in list3:
            pp = Attitude.query.filter_by(user_id=g.user_id, article_id=i.id).first()  # 查询用户对文章的态度记录
            if pp and pp.attitude == 1:
                like = True
            else:
                like = False
            list2.append(
                {
                    "art_id": i.id,
                    "title": i.title,
                    "aut_id": i.user.id,
                    "aut_name": i.user.name,
                    "aut_photo": i.user.profile_photo,
                    "pubdate": str(i.ctime),
                    'cover': i.cover,
                    "images": [],
                    "is_liking": like
                }
            )
        return {'message': "ok",
                'data': {
                    'total_count': len(list2),
                    'results': list2
                }
            }



class CommentView(Resource):
    def post(self):
        data = json.loads(request.data.decode())  # 从请求数据中解析JSON
        target = data.get('target')  # 获取目标值
        content = data.get('content')  # 获取内容
        article_id = data.get('article_id')  # 获取文章ID
        try:
            parent_id = data.get('parent_id')  # 尝试获取父评论ID
            aa = Comment(user_id=g.user_id, article_id=target, content=content, parent_id=parent_id)  # 创建评论对象
            db.session.add(aa)  # 将评论对象添加到数据库会话
            db.session.commit()  # 提交数据库会话
        except:
            aa = Comment(user_id=g.user_id, article_id=target, content=content, parent_id=article_id)  # 创建评论对象
            db.session.add(aa)  # 将评论对象添加到数据库会话
            db.session.commit()  # 提交数据库会话
        return {'message': 'ok', 'data': {'com_id': aa.content, 'target': aa.id}}  # 返回成功消息和评论ID


    def get(self):
        data = request.args  # 获取请求参数
        type = data.get('type')  # 获取类型
        source = data.get('source')  # 获取来源
        offset = data.get('offset')  # 获取偏移量
        limit = data.get('limit')  # 获取限制数量

        if type == 'a':  # 如果类型为'a'
            data = Comment.query.filter_by(article_id=source, parent_id=None).order_by(desc(Comment.ctime)).offset(
                offset).limit(limit).all()  # 查询文章相关的顶级评论
        elif type == 'c':  # 如果类型为'c'
            data = Comment.query.filter_by(parent_id=source).order_by(desc(Comment.ctime)).offset(offset).limit(
                limit).all()  # 查询指定父评论的子评论
        list = []
        for i in data:
            list.append({
                "com_id": i.id,
                "aut_id": i.user.id,
                "aut_name": i.user.name,
                "aut_photo": i.user.profile_photo,
                "pubdate": str(i.ctime),
                "content": i.content,
                "is_top": i.is_top,
                "is_liking": 0
            }
            )
        return {'message': 'ok', 'data': {'total_count': len(list), 'end_id': 108, 'last_id': 108, 'results': list}}  # 返回成功消息和评论数据



class HistoriesView(Resource):
    def get(self):
        qq = Read.query.all()  # 从数据库中读取所有阅读数据
        list = []
        for i in qq:  # 遍历每个阅读记录
            pp = Article.query.get(i.article_id)  # 获取相关文章信息
            list.append({
                "art_id": pp.user.id,  # 文章作者ID
                "title": pp.title,  # 文章标题
                "aut_id": pp.user.id,  # 作者ID
                "aut_name": pp.user.name,  # 作者名称
                "aut_photo": pp.user.profile_photo,  # 作者头像
                "pubdate": str(pp.ctime),  # 发布日期
            }
            )
        return {'message': "ok",
                'data': {
                    'total_count': len(list),  # 总数量
                    'results': list  # 结果列表
                }
            }



class AAA(Resource):
    @login_required
    def get(self):
        data = request.args  # 查询参数
        page = int(data.get('page', 1))  # 页数，默认是1
        per_page = int(data.get("per_page", 10))  # 每页数量
        userRelationships = Relation.query.filter_by(user_id=g.user_id).all()  # 所有数据

        start = (page - 1) * per_page  # 第一条数据
        end = start + per_page  # 最后一条数据
        total_count = len(userRelationships)  # 总数据量
        DataList = userRelationships[start:end]  # 当前页的所有数据
        total_pages = ceil(total_count / per_page)  # 计算总页数

        results = []
        for i in DataList:
            user1 = User.query.get(i.target_user_id)  # 用户表
            fans_count = Relation.query.filter_by(target_user_id=i.target_user_id).count()  # 我关注的人数
            target_user = Relation.query.filter_by(target_user_id=i.target_user_id).first()  # 获取 关注的对象
            mutual_follow = Relation.query.filter_by(user_id=target_user.target_user_id,  # 查询id是否为粉丝的,关注的id为我
                                                     target_user_id=g.user_id).first()  # 查询对方是否关注了我

            results.append({
                "id": user1.id,
                "name": user1.name,
                "photo": user1.profile_photo,
                "fans_count": fans_count,  # 粉丝数量
                "mutual_follow": False if mutual_follow is None else True  # 是否为互相关注
            })
        return {"message": "OK",
                "data": {
                    "total_count": total_count,
                    "page": page,
                    "per_page": per_page,
                    "results": results}}


class FollowView(Resource):
    def get(self):
        data = request.args  # 查询参数
        page = int(data.get('page', 1))  # 页数，默认是1
        per_page = int(data.get("per_page", 10))  # 每页数量
        userRelationships = Relation.query.filter_by(target_user_id=g.user_id).all()  # 所有数据

        start = (page - 1) * per_page  # 第一条数据
        end = start + per_page  # 最后一条数据
        total_count = len(userRelationships)  # 总数据量
        DataList = userRelationships[start:end]  # 当前页的所有数据
        total_pages = ceil(total_count / per_page)  # 计算总页数

        results = []
        for i in DataList:
            user1 = User.query.get(i.target_user_id)  # 用户表
            mutual_follow = Relation.query.filter_by(target_user_id=i.user_id, relation=1,
                                                     user_id=g.user_id)  # 查询id是否为粉丝的,关注的id为我
            # 查询对方是否关注了我

            results.append({
                "id": user1.id,
                "name": user1.name,
                "photo": user1.profile_photo,
                "fans_count": 1,  # 粉丝数量
                "mutual_follow": False if mutual_follow is None else True  # 是否为互相关注
            })
        return {"message": "OK",
                "data": {
                    "total_count": total_count,
                    "page": page,
                    "per_page": per_page,
                    "results": results}}
